package com.tianji.learning.service.impl;

import cn.hutool.core.io.unit.DataUnit;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.constants.RedisConstants;
import com.tianji.learning.domain.po.PointsRecord;
import com.tianji.learning.domain.vo.PointsStatisticsVO;
import com.tianji.learning.enums.PointsRecordType;
import com.tianji.learning.mapper.PointsRecordMapper;
import com.tianji.learning.service.IPointsRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.lang.reflect.Type;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 学习积分记录，每个月底清零 服务实现类
 * </p>
 *
 * @author huanghui
 * @since 2023-07-29
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class PointsRecordServiceImpl extends ServiceImpl<PointsRecordMapper, PointsRecord> implements IPointsRecordService {
    private final StringRedisTemplate redisTemplate;
    @Override
    public void addPointsRecords(Long userId, int points, PointsRecordType type) {
        log.info("添加学习积分");
        LocalDateTime now = LocalDateTime.now();
        int maxPoints = type.getMaxPoints();
        int  realPoints=points;
        //1.判断当前积分有没有积分上限
        if (maxPoints>0){
            //2.有，则需要判断是否超过上线
            //2.1.查询今天获取的积分
            LocalDateTime begin = DateUtils.getDayStartTime(now);
            LocalDateTime end = DateUtils.getDayEndTime(now);
            int currentPoints = queryUserPointsByTypeAndDate(userId, type, begin, end);
            //2.2.判断是否超过上限
            if (currentPoints>=maxPoints){
                //2.3.超过，直接结束
                return;
            }
            //2.4 没有超过，保存积分记录
            if(currentPoints+points>maxPoints){
                realPoints=maxPoints-currentPoints;
            }
        }

        //3.没有超过，则保存当前积分记录
        PointsRecord p = new PointsRecord();
        p.setPoints(realPoints);
        p.setUserId(userId);
        p.setType(type);
        save(p);
        //4.更新积分到redis当中
        String key=RedisConstants.POINTS_BOARD_KEY_PREFIX+
                now.format(DateUtils.POINTS_BOARD_SUFFIX_PREFIX);
        redisTemplate.opsForZSet().incrementScore(key,userId.toString(),realPoints);
    }

    @Override
    public List<PointsStatisticsVO> queryMyPointsToday() {
        //1.获取用户
        Long userId = UserContext.getUser();
        //2.获取日期
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime begin = DateUtils.getDayStartTime(now);
        LocalDateTime end = DateUtils.getDayEndTime(now);
        //3.构建查询语句
        QueryWrapper<PointsRecord> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(PointsRecord::getUserId,userId)
                .between(PointsRecord::getCreateTime,begin,end);
        //4.查询结果
          /*
        使用  ${ew.customSqlSegment} 自动构建wrapper里面的查询语句
        必须使用  @Param(Constants.WRAPPER) 参数才能知道
         */
        List<PointsRecord>  list= getBaseMapper().queryUserPointsByDate(wrapper);
        //4.1 健壮性判断
        if (CollUtils.isEmpty(list)) {
            return CollUtils.emptyList();
        }
        //5.封装返回
        List<PointsStatisticsVO> voList = new ArrayList<>(list.size());
        for (PointsRecord p : list) {
            PointsStatisticsVO vo = new PointsStatisticsVO();
            vo.setType(p.getType().getDesc());
            vo.setMaxPoints(p.getType().getMaxPoints());
            vo.setPoints(p.getPoints());
            voList.add(vo);
        }
        return voList;
    }

    private int queryUserPointsByTypeAndDate(Long userId, PointsRecordType type, LocalDateTime begin, LocalDateTime end) {
        //1.查询条件
        QueryWrapper<PointsRecord> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(PointsRecord::getUserId,userId)
                        .eq(type!=null,PointsRecord::getType,type)
                        .between(begin!=null&&end!=null,PointsRecord::getCreateTime,begin,end);

        /*
        使用  ${ew.customSqlSegment} 自动构建wrapper里面的查询语句
        必须使用  @Param(Constants.WRAPPER) 参数才能知道
         */
        //2.调用mapper 查询结果
        Integer points=getBaseMapper().queryUserPointsByTypeAndDate(wrapper);
        //3.判断并返回
        return points==null?0:points;
    }
}
